﻿#include "stdafx.h"
/// Copyright 2012, Alex Averian, Yonan Research
/// Released under BSD Licence


#include <comdef.h>
#include <shlwapi.h> ///QISearch

#include "qcom.h"

using namespace micro::com;

 
 

// 
// inline HRESULT QSafeArrayGetActualVartype( _In_ SAFEARRAY * psaArray, _Out_ VARTYPE * pvtType )
// {
//     HRESULT hrSystem =::SafeArrayGetVartype( psaArray, pvtType );
// 
//     if ( FAILED( hrSystem ) )
//     {
//         return hrSystem;
//     }
// 
//     /*
//     When Windows has a SAFEARRAY of type VT_DISPATCH with FADF_HAVEIID,
//     it returns VT_UNKNOWN instead of VT_DISPATCH. We patch the value to be correct
//     */
//     if ( pvtType && *pvtType == VT_UNKNOWN )
//     {
//         if ( psaArray && ( ( psaArray->fFeatures & FADF_HAVEIID ) != 0 ) )
//         {
//             if ( psaArray->fFeatures & FADF_DISPATCH )
//             {
//                 *pvtType = VT_DISPATCH;
//             }
//         }
//     }
// 
//     return hrSystem;
// }
// 
// 
// QComVariant::QComVariant( _In_ const SAFEARRAY * pSrc )
// {
// 	ASSERT( pSrc != nullptr );
// 
// 	if ( pSrc == nullptr )
// 	{
// 		vt = VT_ERROR;
// 		scode = E_INVALIDARG;
// 
// 	}
// 	else
// 	{
// 		LPSAFEARRAY pCopy;
// 		HRESULT hRes = ::SafeArrayCopy( ( LPSAFEARRAY )pSrc, &pCopy );
// 
// 		if ( SUCCEEDED( hRes ) )
// 		{
// 			QSafeArrayGetActualVartype( ( LPSAFEARRAY )pSrc, &vt );
// 			vt |= VT_ARRAY;
// 			parray = pCopy;
// 		}
// 		else
// 		{
// 			vt = VT_ERROR;
// 			scode = hRes;
// 
// 			throw( hRes );
// 
// 
// 		}
// 	}
// }
// 
// 
// QComVariant & QComVariant::operator=( _In_ const SAFEARRAY * pSrc )
// {
// 	ASSERT( pSrc != nullptr );
// 
// 	if ( pSrc == nullptr )
// 	{
// 		ClearThrow();
// 		vt = VT_ERROR;
// 		scode = E_INVALIDARG;
// 
// 		throw( E_INVALIDARG );
// 
// 	}
// 	else
// 		if ( ( vt & VT_ARRAY ) == 0 || pSrc != parray )
// 		{
// 			ClearThrow();
// 			LPSAFEARRAY pCopy;
// 			HRESULT hr = ::SafeArrayCopy( ( LPSAFEARRAY )pSrc, &pCopy );
// 
// 			if ( SUCCEEDED( hr ) )
// 			{
// 				QSafeArrayGetActualVartype( ( LPSAFEARRAY )pSrc, &vt );
// 				vt |= VT_ARRAY;
// 				parray = pCopy;
// 			}
// 			else
// 			{
// 				vt = VT_ERROR;
// 				scode = hr;
// 
// 				throw( hr );
// 
// 			}
// 		}
// 
// 		return *this;
// }
// 
// #ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
// 
// #pragma warning(push)
// #pragma warning(disable: 4702)
// _Check_return_ inline HRESULT QComVariant::WriteToStream( _Inout_ IStream * pStream )
// {
//     if ( pStream == NULL )
//         return E_INVALIDARG;
// 
//     HRESULT hr = pStream->Write( &vt, sizeof( VARTYPE ), NULL );
// 
//     if ( FAILED( hr ) )
//         return hr;
// 
//     int cbWrite = 0;
// 
//     switch ( vt )
//     {
//         case VT_UNKNOWN:
//         case VT_DISPATCH:
//             {
//                 QComPointer<IPersistStream> spStream;
// 
//                 if ( punkVal != NULL )
//                 {
//                     hr = punkVal->QueryInterface( __uuidof( IPersistStream ), ( void ** )&spStream );
// 
//                     if ( FAILED( hr ) )
//                     {
//                         hr = punkVal->QueryInterface( __uuidof( IPersistStreamInit ), ( void ** )&spStream );
// 
//                         if ( FAILED( hr ) )
//                         {
//                             spStream.Detach();
//                             return hr;
//                         }
//                     }
//                 }
// 
//                 if ( spStream != NULL )
//                     return OleSaveToStream( spStream, pStream );
// 
//                 return WriteClassStm( pStream, CLSID_NULL );
//             }
// 
//         case VT_UI1:
//         case VT_I1:
//             cbWrite = sizeof( BYTE );
//             break;
// 
//         case VT_I2:
//         case VT_UI2:
//         case VT_BOOL:
//             cbWrite = sizeof( short );
//             break;
// 
//         case VT_I4:
//         case VT_UI4:
//         case VT_R4:
//         case VT_INT:
//         case VT_UINT:
//         case VT_ERROR:
//             cbWrite = sizeof( long );
//             break;
// 
//         case VT_I8:
//         case VT_UI8:
//             cbWrite = sizeof( LONGLONG );
//             break;
// 
//         case VT_R8:
//         case VT_CY:
//         case VT_DATE:
//             cbWrite = sizeof( double );
//             break;
// 
//         default
//                 :
//             break;
//     }
// 
//     if ( cbWrite != 0 )
//         return pStream->Write( ( void * ) &bVal, cbWrite, NULL );
// 
//     QBstr bstrWrite;
//     QComVariant varBSTR;
// 
//     if ( vt != VT_BSTR )
//     {
//         hr = VariantChangeType( &varBSTR, this, VARIANT_NOVALUEPROP, VT_BSTR );
// 
//         if ( FAILED( hr ) )
//             return hr;
// 
//         bstrWrite.Attach( varBSTR.bstrVal );
//     }
//     else
//         bstrWrite.Attach( bstrVal );
// 
//     hr = bstrWrite.WriteToStream( pStream );
//     bstrWrite.Detach();
//     return hr;
// }
// #pragma warning(pop)	// C4702
// 
// 
// _Check_return_ inline HRESULT QComVariant::ReadFromStream(
//     _Inout_ IStream * pStream,
//     _In_ VARTYPE vtExpected /* = VT_EMPTY */ )
// {
//     ClassesAllowedInStream allowed;
//     allowed.rgclsidAllowed = NULL;
// 
//     return ReadFromStream( pStream, vtExpected, allowed, 0 );
// }
// 
// _Check_return_ inline HRESULT QComVariant::ReadFromStream(
//     _Inout_ IStream * pStream,
//     _In_ VARTYPE vtExpected,
//     _In_ ClassesAllowedInStream rgclsidAllowed,
//     _In_ DWORD cclsidAllowed )
// {
//     ASSERT( pStream != NULL );
// 
//     if ( pStream == NULL )
//         return E_INVALIDARG;
// 
//     HRESULT hr;
//     hr = VariantClear( this );
// 
//     if ( FAILED( hr ) )
//         return hr;
// 
//     VARTYPE vtRead = VT_EMPTY;
//     ULONG cbRead = 0;
// 
//     hr = pStream->Read( &vtRead, sizeof( VARTYPE ), &cbRead );
// 
//     if ( hr == S_FALSE || ( cbRead != sizeof( VARTYPE ) && hr == S_OK ) )
//         hr = E_FAIL;
// 
//     if ( FAILED( hr ) )
//         return hr;
// 
//     if ( vtExpected != VT_EMPTY && vtRead != vtExpected )
//         return E_FAIL;
// 
//     vt = vtRead;
//     cbRead = 0;
// 
//     switch ( vtRead )
//     {
//         case VT_UNKNOWN:
//         case VT_DISPATCH:
//             {
//                 punkVal = NULL;
//                 hr = AtlInternalOleLoadFromStream( pStream,
//                                                    ( vtRead == VT_UNKNOWN ) ? __uuidof( IUnknown ) : __uuidof( IDispatch ),
//                                                    ( void ** )&punkVal, rgclsidAllowed, cclsidAllowed );
// 
//                 // If IPictureDisp or IFontDisp property is not set,
//                 // OleLoadFromStream() will return REGDB_E_CLASSNOTREG.
//                 if ( hr == REGDB_E_CLASSNOTREG )
//                     hr = S_OK;
// 
//                 return hr;
//             }
// 
//         case VT_UI1:
//         case VT_I1:
//             cbRead = sizeof( BYTE );
//             break;
// 
//         case VT_I2:
//         case VT_UI2:
//         case VT_BOOL:
//             cbRead = sizeof( short );
//             break;
// 
//         case VT_I4:
//         case VT_UI4:
//         case VT_R4:
//         case VT_INT:
//         case VT_UINT:
//         case VT_ERROR:
//             cbRead = sizeof( long );
//             break;
// 
//         case VT_I8:
//         case VT_UI8:
//             cbRead = sizeof( LONGLONG );
//             break;
// 
//         case VT_R8:
//         case VT_CY:
//         case VT_DATE:
//             cbRead = sizeof( double );
//             break;
// 
//         default
//                 :
//             break;
//     }
// 
//     if ( cbRead != 0 )
//     {
//         hr = pStream->Read( ( void * ) &bVal, cbRead, NULL );
// 
//         if ( hr == S_FALSE )
//             hr = E_FAIL;
// 
//         return hr;
//     }
// 
//     QBstr bstrRead;
// 
//     hr = bstrRead.ReadFromStream( pStream );
// 
//     if ( FAILED( hr ) )
//     {
//         // If QBstr::ReadFromStream failed, reset seek pointer to start of
//         // variant type.
//         LARGE_INTEGER nOffset;
//         nOffset.QuadPart = -( static_cast<LONGLONG>( sizeof( VARTYPE ) ) );
//         pStream->Seek( nOffset, STREAM_SEEK_CUR, NULL );
//         vt = VT_EMPTY;
//         return hr;
//     }
// 
//     vt = VT_BSTR;
//     bstrVal = bstrRead.Detach();
// 
//     if ( vtRead != VT_BSTR )
//         hr = ChangeType( vtRead );
// 
//     return hr;
// }
// 
// inline HRESULT QComVariant::GetSizeMax( _Out_ ULARGE_INTEGER * pcbSize ) const
// {
//     ASSERT( pcbSize != NULL );
// 
//     if ( pcbSize == NULL )
//     {
//         return E_INVALIDARG;
//     }
// 
//     HRESULT hr = S_OK;
//     ULARGE_INTEGER nSize;
//     nSize.QuadPart = sizeof( VARTYPE );
// 
//     switch ( vt )
//     {
//         case VT_UNKNOWN:
//         case VT_DISPATCH:
//             {
//                 nSize.LowPart += sizeof( CLSID );
// 
//                 if ( punkVal != NULL )
//                 {
//                     QComPointer<IPersistStream> spStream;
// 
//                     hr = punkVal->QueryInterface( __uuidof( IPersistStream ), ( void ** )&spStream );
// 
//                     if ( FAILED( hr ) )
//                     {
//                         hr = punkVal->QueryInterface( __uuidof( IPersistStreamInit ), ( void ** )&spStream );
// 
//                         if ( FAILED( hr ) )
//                         {
//                             break;
//                         }
//                     }
// 
//                     ULARGE_INTEGER nPersistSize;
//                     nPersistSize.QuadPart = 0;
// 
//                     ASSERT( spStream != NULL );
//                     hr = spStream->GetSizeMax( &nPersistSize );
// 
//                     if ( SUCCEEDED( hr ) )
//                     {
//                         hr = AtlAdd( &nSize.QuadPart, nSize.QuadPart, nPersistSize.QuadPart );
//                     }
//                 }
//             }
//             break;
// 
//         case VT_UI1:
//         case VT_I1:
//             nSize.LowPart += sizeof( BYTE );
//             break;
// 
//         case VT_I2:
//         case VT_UI2:
//         case VT_BOOL:
//             nSize.LowPart += sizeof( short );
//             break;
// 
//         case VT_I4:
//         case VT_UI4:
//         case VT_R4:
//         case VT_INT:
//         case VT_UINT:
//         case VT_ERROR:
//             nSize.LowPart += sizeof( long );
//             break;
// 
//         case VT_I8:
//         case VT_UI8:
//             nSize.LowPart += sizeof( LONGLONG );
//             break;
// 
//         case VT_R8:
//         case VT_CY:
//         case VT_DATE:
//             nSize.LowPart += sizeof( double );
//             break;
// 
//         default
//                 :
//             {
//                 VARTYPE vtTmp = vt;
//                 BSTR bstr = NULL;
//                 QComVariant varBSTR;
// 
//                 if ( vtTmp != VT_BSTR )
//                 {
//                     hr = VariantChangeType( &varBSTR, const_cast<VARIANT *>( ( const VARIANT * )this ), VARIANT_NOVALUEPROP, VT_BSTR );
// 
//                     if ( SUCCEEDED( hr ) )
//                     {
//                         bstr = varBSTR.bstrVal;
//                         vtTmp = VT_BSTR;
//                     }
//                 }
//                 else
//                 {
//                     bstr = bstrVal;
//                 }
// 
//                 if ( vtTmp == VT_BSTR )
//                 {
//                     // Add the size of the length + string (in bytes) + NULL terminator.
//                     nSize.QuadPart += QBstr::GetStreamSize( bstr );
//                 }
//             }
//     }
// 
//     if ( SUCCEEDED( hr ) )
//     {
//         pcbSize->QuadPart = nSize.QuadPart;
//     }
// 
//     return hr;
// }
// 
// inline ATL_DEPRECATED( "GetSize has been replaced by GetSizeMax" )
// ULONG QComVariant::GetSize() const
// {
//     ULARGE_INTEGER nSize;
//     HRESULT hr = GetSizeMax( &nSize );
// 
//     if ( SUCCEEDED( hr ) && nSize.QuadPart <= ULONG_MAX )
//     {
//         return nSize.LowPart;
//     }
// 
//     return sizeof( VARTYPE );
// }
// 
// _Check_return_ inline HRESULT QComPointer<IDispatch>::Invoke2(
//     _In_ DISPID dispid,
//     _In_ VARIANT * pvarParam1,
//     _In_ VARIANT * pvarParam2,
//     _Out_opt_ VARIANT * pvarRet ) throw()
// {
//     if ( pvarParam1 == NULL || pvarParam2 == NULL )
//         return E_INVALIDARG;
// 
//     QComVariant varArgs[2] = { *pvarParam2, *pvarParam1 };
//     DISPPARAMS dispparams = { &varArgs[0], NULL, 2, 0};
//     return p->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL );
// }
// 
// #endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP

/*
    Workaround for VarCmp function which does not compare VT_I1, VT_UI2, VT_UI4, VT_UI8 values
*/
// inline HRESULT QComVariant::VarCmp(
//     _In_ LPVARIANT pvarLeft,
//     _In_ LPVARIANT pvarRight,
//     _In_ LCID lcid,
//     _In_ ULONG dwFlags ) const throw()
// {
//     switch ( vt )
//     {
//         case VT_I1:
//             if ( pvarLeft->cVal == pvarRight->cVal )
//             {
//                 return VARCMP_EQ;
//             }
// 
//             return pvarLeft->cVal > pvarRight->cVal ? VARCMP_GT : VARCMP_LT;
// 
//         case VT_UI2:
//             if ( pvarLeft->uiVal == pvarRight->uiVal )
//             {
//                 return VARCMP_EQ;
//             }
// 
//             return pvarLeft->uiVal > pvarRight->uiVal ? VARCMP_GT : VARCMP_LT;
// 
//         case VT_UI4:
//             if ( pvarLeft->uintVal == pvarRight->uintVal )
//             {
//                 return VARCMP_EQ;
//             }
// 
//             return pvarLeft->uintVal > pvarRight->uintVal ? VARCMP_GT : VARCMP_LT;
// 
//         case VT_UI8:
//             if ( pvarLeft->ullVal == pvarRight->ullVal )
//             {
//                 return VARCMP_EQ;
//             }
// 
//             return pvarLeft->ullVal > pvarRight->ullVal ? VARCMP_GT : VARCMP_LT;
// 
//         default
//                 :
//             return ::VarCmp( pvarLeft, pvarRight, lcid, dwFlags );
//     }
// }

#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP

ATLPREFAST_SUPPRESS( 6387 )
_Check_return_ inline HRESULT AtlInternalOleLoadFromStream(
    _Inout_ IStream * pStm,
    _In_ REFIID iidInterface,
    _Outptr_ void ** ppvObj,
    _In_ ClassesAllowedInStream rgclsidAllowed,
    _In_ DWORD cclsidAllowed )
{
    ATLASSUME( pStm != NULL );
    *ppvObj = NULL;
    CLSID clsid;

    HRESULT hr = ReadClassStm( pStm, &clsid );

    if ( FAILED( hr ) )
    {
        return hr;
    }

    QComPointer<IUnknown> punkVal;

    if ( cclsidAllowed != 0 )
    {
        ATLASSUME( rgclsidAllowed.rgclsidAllowed != NULL );
        hr = E_ACCESSDENIED;

        for ( DWORD i = 0; i < cclsidAllowed; i++ )
        {
            if ( IsEqualCLSID( clsid, rgclsidAllowed.rgclsidAllowed[i] ) )
            {
                hr = S_OK;
                break;
            }
        }
    }
    else
        if ( rgclsidAllowed.pfnClsidAllowed != NULL )
        {
            hr = rgclsidAllowed.pfnClsidAllowed( clsid, iidInterface, reinterpret_cast<void **>( &punkVal ) );
        }

    if ( FAILED( hr ) )
    {
        return hr;
    }

    if ( punkVal == NULL )
    {
        hr = CoCreateInstance( clsid, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, iidInterface, reinterpret_cast<void **>( &punkVal ) );

        if ( FAILED( hr ) )
        {
            return hr;
        }
    }

    QComPointer<IPersistStream> pPersistStm;
    hr = punkVal->QueryInterface( &pPersistStm );

    if ( SUCCEEDED( hr ) )
    {
        hr = pPersistStm->Load( pStm );

        if ( SUCCEEDED( hr ) )
        {
            *ppvObj = punkVal.Detach();
        }
    }

    return hr;
}
 
#endif